#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <assert.h>

#include "frame.h"

#define FRAME_TYPE_STR(type) (((type)==FRAME_TYPE_I)?"I":"P")
static int get_video_frame(video_frame_header *video_data,int srclen,struct stream_frame_status *video_frame)
{
    unsigned char *frame = video_frame->frame;
    int deslen = sizeof(video_frame->frame);
    int pack_cache_size = video_frame->pack_cache_size;

    if(pack_cache_size>0)
    {
	video_frame->new_frame_flag = 0;

	video_frame->begin_pnum = video_frame->header.pack_num;
	video_frame->end_pnum = video_frame->begin_pnum;
	video_frame->total_pack = 1;
	video_frame->frame_size = pack_cache_size;

	memcpy((void*)frame,video_frame->pack_cache,pack_cache_size);
	video_frame->pack_cache_size = 0; /* reset cache */
    }
    else if(video_frame->new_frame_flag)
    {/* start a new frame,reinitialize the @video_frame@ struct */
	video_frame->new_frame_flag = 0;

	video_frame->begin_pnum = -1;
	video_frame->end_pnum = video_frame->begin_pnum;
	video_frame->total_pack = 0;
	video_frame->frame_size = 0;

	memset(&video_frame->header,0,sizeof(video_frame_header));
	memset((void*)frame,0,deslen);
	memset((void*)video_frame->pack_cache,0,sizeof(video_frame->pack_cache));
	video_frame->pack_cache_size = 0; /* reset cache */
    }

    int prev_frame_type = video_frame->header.frame_type;
    int prev_frame_len = video_frame->header.frame_len;
    int last_pnum = video_frame->header.pack_num;

    int frame_size = video_frame->frame_size;
    int begin_pnum = video_frame->begin_pnum;
    int end_pnum  = video_frame->end_pnum;
    int total_pack = video_frame->total_pack;

    struct timeval now;
    int frame_flag = 0;
    int frame_type = video_data->frame_type;
    int video_len = srclen-sizeof(video_frame_header);
    unsigned char *data_addr = (unsigned char *)video_data+sizeof(video_frame_header);

    //printf("+++pack num:%d,frame type:%s,video len:%d,frame len:%d\n",
    //	    video_data->pack_num,FRAME_TYPE_STR(frame_type),video_len,video_data->frame_len);
    if(frame==NULL||deslen<video_len)
    {
	printf("!!!video pack len:%d\n",video_len);
	video_frame->frame_size  = 0;
	return 0;
    }

    /****** BEGIN:only GOT NEXT Frame Pack,We can Check LAST Frame,so we must cache a pack ****/
    if(((prev_frame_type!=frame_type)||(last_pnum>=video_data->pack_num))
	&& frame_size>0)
    {
	char case_str[8];
	if(prev_frame_type!=frame_type)
	{ /* check if we got a frame by FRAME TYPE has changed.
	BUG: Maybe Two Frame is SAME TYPE. */
	    strcpy(case_str,"1");
	}
	else
	{ /* check if we got a frame by FRAME PACK NUMBER begins again.
	BUG: PACK lost cause MESS */
	    strcpy(case_str,"2");
	}
	gettimeofday(&now,NULL);
	end_pnum = last_pnum; 
	frame_flag = 1;
	printf(">>>[%s][%ld.%03ld]video frame[%s] size %d B,pnum[%d = %d - %d+1]![%d(want)]\n",
		case_str,now.tv_sec,now.tv_usec/1000,FRAME_TYPE_STR(prev_frame_type),
		frame_size, total_pack,end_pnum,begin_pnum,prev_frame_len); 
	video_frame->frame_size = frame_size; /* got frame */

	/*** backup last Video Frame Pack Info for next frame build ***/
	memcpy(&video_frame->header,video_data,sizeof(video_frame_header));
    
	/* cache this pack */
	memcpy((void*)video_frame->pack_cache,data_addr,video_len);
	video_frame->pack_cache_size = video_len;

	video_frame->new_frame_flag = frame_flag;
	return frame_flag;
    }
    else
    { /*** backup last Video Frame Pack Info for next frame build ***/
	memcpy(&video_frame->header,video_data,sizeof(video_frame_header));
    }

    total_pack++;
    if(frame_size+video_len > deslen)
    {
	printf("!!!!!!!!Frame buffer [%d] not enough!!!!\n",deslen);
	video_frame->frame_size = frame_size;
    }
    else
    {
	memcpy((void*)(frame+frame_size),data_addr,video_len);
    }
    frame_size += video_len;

    if(begin_pnum<0)
    {
	begin_pnum = video_data->pack_num;
	//int i = 0;
	//for(i=0;i<100;i++)
	//    printf("%#x ",*((unsigned char *)video_data+i));
	//printf("\n");
    }

    if(frame_size == video_data->frame_len)
    {/* check if we got a frame by FRAME SIZE is OK. 
	BUG: FRAME SIZE maybe not EQUALITY,see above TWO Check Method case result.
     */
	gettimeofday(&now,NULL);
	end_pnum = video_data->pack_num;
	frame_flag = 1; // we got a frame
	//printf(">>>[3][%d.%03d]video frame[%s] size %d B,pnum[%d = %d - %d+1]!\n",
	//	now.tv_sec,now.tv_usec/1000,(frame_type==FRAME_TYPE_I)?"I":"P",frame_size,
	//	total_pack,end_pnum,begin_pnum); 
	if(video_frame->first_frame_flag && frame_type!=FRAME_TYPE_I)
	    frame_flag = 0;
	else if(video_frame->first_frame_flag)
	    video_frame->first_frame_flag = 0;
	
	video_frame->frame_size = frame_size;
	video_frame->new_frame_flag = 1; /* next to check new frame */
    }

    /** update info **/
    video_frame->begin_pnum = begin_pnum;
    video_frame->end_pnum = end_pnum;
    video_frame->frame_size = frame_size;
    video_frame->total_pack = total_pack;

    return frame_flag;
}

int get_stream_frame(struct stream_frame_status *stream_frame,char *buf, int len)
{
    struct meian_pkg_head_type *pkg_head = (struct meian_pkg_head_type *)buf;
    int ret = 0;

    //printf("----buf = %p,len = %d;head.len = %d,head.cmd = %#x\n",buf,len,pkg_head->len,pkg_head->cmd);
    if(CMD_VIDEO_TRNS==pkg_head->cmd)
    {
	video_frame_header *video_data = (video_frame_header*)(buf+MA_PKG_HEAD_SIZE);
	ret = get_video_frame(video_data,pkg_head->len,stream_frame);
	if(ret==1 && stream_frame->frame_size>0)
	{
	   //printf("---fts[%d] = %d:%d:%d\n",video_data->fts,(video_data->fts>>16)&0xff,(video_data->fts>>8)&0xff,video_data->fts&0xff);
	   ret = STREAM_FRAME_VIDEO; /* we got a frame: stream_frame->frame,stream_frame->frame_size */
	}
    }
    else if(CMD_MONITOR_DATA_TRANS==pkg_head->cmd)
    {
	char *audio_frame = NULL;
	//printf("---audio frame len = %d\n",pkg_head->len);
	audio_frame = buf+MA_PKG_HEAD_SIZE;
	memcpy(stream_frame->audio_frame,audio_frame,pkg_head->len);
	stream_frame->audio_frame_size = pkg_head->len;	
	ret = STREAM_FRAME_AUDIO;
    }

    return ret;
} 

int init_stream_frame_status(struct stream_frame_status *stream_frame)
{
    assert(stream_frame);
    stream_frame->new_frame_flag = 1;
    stream_frame->first_frame_flag = 1;
    stream_frame->pack_cache_size = 0;
    return 0;
}

